package com.mp.chart.charts;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.mp.chart.components.AJXAxis;
import com.mp.chart.components.AJYAxis;
import com.mp.chart.components.MarkerView;
import com.mp.chart.components.YAxis;
import com.mp.chart.data.AJData;
import com.mp.chart.data.BarData;
import com.mp.chart.data.BollData;
import com.mp.chart.data.BubbleData;
import com.mp.chart.data.BubbleDataSet;
import com.mp.chart.data.CandleData;
import com.mp.chart.data.CandleEntry;
import com.mp.chart.data.Entry;
import com.mp.chart.data.LineData;
import com.mp.chart.data.LineDataSet;
import com.mp.chart.data.SarData;
import com.mp.chart.data.ScatterData;
import com.mp.chart.formatter.FillFormatter;
import com.mp.chart.interfaces.AJProvider;
import com.mp.chart.interfaces.BarDataProvider;
import com.mp.chart.interfaces.BollDataProvider;
import com.mp.chart.interfaces.BubbleDataProvider;
import com.mp.chart.interfaces.CandleDataProvider;
import com.mp.chart.interfaces.LineDataProvider;
import com.mp.chart.interfaces.SarDataProvider;
import com.mp.chart.interfaces.ScatterDataProvider;
import com.mp.chart.listener.AJChartTouchListener;
import com.mp.chart.listener.ChartTouchListener;
import com.mp.chart.listener.OnScrollDataListener;
import com.mp.chart.listener.OnSyncChartListener;
import com.mp.chart.markerview.HightCircleMarkerView;
import com.mp.chart.markerview.LoadingMarkerView;
import com.mp.chart.markerview.ValueMarkerView;
import com.mp.chart.renderer.AJChartRenderer;
import com.mp.chart.renderer.AJXAxisRenderer;
import com.mp.chart.renderer.AJYAxisRenderer;
import com.mp.chart.utils.Highlight;
import com.mp.chart.utils.Utils;

import java.util.List;

/**
 * K线chart
 * Created by TenFace on 2017/9/26.
 */
public class KLineChart extends BarLineChartBase<AJData> implements LineDataProvider,
        BarDataProvider, ScatterDataProvider, CandleDataProvider, BubbleDataProvider, SarDataProvider, AJProvider, BollDataProvider {


    protected FillFormatter mFillFormatter;

    private boolean mDrawHighlightArrow = false;

    private boolean mDrawValueAboveBar = true;

    /**
     * if set to true, all values of a stack are drawn individually, and not
     * just their sum
     */
    private boolean mDrawValuesForWholeStack = true;

    /**
     * if set to true, a grey area is drawn behind each bar that indicates the
     * maximum showapi_res_body
     */
    private boolean mDrawBarShadow = false;

    protected DrawOrder[] mDrawOrder = new DrawOrder[]{
            DrawOrder.BAR, DrawOrder.BUBBLE, DrawOrder.LINE, DrawOrder.CANDLE, DrawOrder.POINT, DrawOrder.BOLL, DrawOrder.SAR
    };
    private AJChartTouchListener mKLineTouchListener;
    private HightCircleMarkerView hightCircleMarkerView;
    private MarkerView mMaxVolumeMarkerView;
    private MarkerView mHighValueMarkerView;
    private MarkerView mLowValueMarkerView;
    private MarkerView mQuoteInfoMarkerView;
    private MarkerView mLeftMarkerView;
    private MarkerView mRightMarkerView;
    private OnScrollDataListener mOnScrollDataListener;
    private LoadingMarkerView loadingMarkView;
    private float minXRange = -1;
    private float maxXRange = -1;
    private ValueMarkerView valueMarkerView;
    private boolean markerViewIsVisibility = false;

    private int valueMarkerViewPosition;


    private final int ValueMarkerViewPosition_Left = 1;
    private final int ValueMarkerViewPosition_Right = 2;
    private float mIndicateLength;
    private Paint mIndicatePaint;
    private boolean mHighlightStyle;
    private MarkerView mXAxisMarkerView;
    private MarkerView buttonView;
    private String marketChartType;//com.mp.chart marketChartType

    @Override
    public SarData getSarData() {
        if (mData == null)
            return null;
        return mData.getSarData();
    }

    @Override
    public BollData getBollData() {
        if (mData == null)
            return null;
        return mData.getBollData();
    }


    /**
     * enum that allows to specify the order in which the different data objects
     * for the combined-com.mp.chart are drawn
     */
    public enum DrawOrder {
        BAR, BUBBLE, LINE, CANDLE, SCATTER, SAR, POINT, BOLL
    }

    public KLineChart(Context context, String marketChartType) {
        super(context);
        this.marketChartType = marketChartType;
    }

    public KLineChart(Context context, AttributeSet attrs, String marketChartType) {
        super(context, attrs);
        this.marketChartType = marketChartType;
    }

    public KLineChart(Context context, AttributeSet attrs, int defStyle, String marketChartType) {
        super(context, attrs, defStyle);
        this.marketChartType = marketChartType;
    }

    @Override
    protected void init() {
        super.init();
        mFillFormatter = new DefaultFillFormatter();
        mIndicateLength = Utils.convertDpToPixel(10);
        mIndicatePaint = new Paint();
        mIndicatePaint.setAntiAlias(true);
        mIndicatePaint.setColor(0xff82B6D1);
        mIndicatePaint.setStyle(Paint.Style.STROKE);
        mIndicatePaint.setStrokeWidth(2f);


        setDescription("");
        mXAxis = new AJXAxis();
        mChartTouchListener = new AJChartTouchListener(this, mViewPortHandler.getMatrixTouch());
        mXAxisRenderer = new AJXAxisRenderer(this, mViewPortHandler, (AJXAxis) mXAxis, mLeftAxisTransformer);
        mAxisLeft = new AJYAxis(YAxis.AxisDependency.LEFT);
        mAxisRendererLeft = new AJYAxisRenderer(mViewPortHandler, (AJYAxis) mAxisLeft, mLeftAxisTransformer);

        mKLineTouchListener = (AJChartTouchListener) mChartTouchListener;


    }


    public void restoreSetting() {
        mAxisLeft = new AJYAxis(YAxis.AxisDependency.LEFT);
        mAxisRendererLeft = new AJYAxisRenderer(mViewPortHandler, (AJYAxis) mAxisLeft, mLeftAxisTransformer);
    }


    public void setFillFormatter(FillFormatter formatter) {

        if (formatter == null)
            formatter = new DefaultFillFormatter();
        else
            mFillFormatter = formatter;
    }

    @Override
    public FillFormatter getFillFormatter() {
        return mFillFormatter;
    }

    @Override
    public LineData getLineData() {
        if (mData == null)
            return null;
        return mData.getLineData();
    }

    @Override
    public BarData getBarData() {
        if (mData == null)
            return null;
        return mData.getBarData();
    }

    @Override
    public ScatterData getScatterData() {
        if (mData == null)
            return null;
        return mData.getScatterData();
    }

    @Override
    public CandleData getCandleData() {
        if (mData == null)
            return null;
        return mData.getCandleData();
    }

    @Override
    public BubbleData getBubbleData() {
        if (mData == null)
            return null;
        return mData.getBubbleData();
    }

    @Override
    public boolean isDrawBarShadowEnabled() {
        return mDrawBarShadow;
    }

    @Override
    public boolean isDrawValueAboveBarEnabled() {
        return mDrawValueAboveBar;
    }

    @Override
    public boolean isDrawHighlightArrowEnabled() {
        return mDrawHighlightArrow;
    }

    @Override
    public boolean isDrawValuesForWholeStackEnabled() {
        return mDrawValuesForWholeStack;
    }

    /**
     * If set to true, a grey area is drawn behind each bar that indicates the
     * maximum showapi_res_body. Enabling his will reduce performance by about 50%.
     *
     * @param enabled
     */
    public void setDrawBarShadow(boolean enabled) {
        mDrawBarShadow = enabled;
    }

    /**
     * Returns the currently set draw order.
     *
     * @return
     */
    public DrawOrder[] getDrawOrder() {
        return mDrawOrder;
    }

    /**
     * Sets the order in which the provided data objects should be drawn. The
     * earlier you place them in the provided array, the further they will be in
     * the background. e.g. if you provide new DrawOrer[] { DrawOrder.BAR,
     * DrawOrder.LINE }, the bars will be drawn behind the lines.
     *
     * @param order
     */
    public void setDrawOrder(DrawOrder[] order) {
        if (order == null || order.length <= 0)
            return;
        mDrawOrder = order;
    }

    protected class DefaultFillFormatter implements FillFormatter {

        @Override
        public float getFillLinePosition(LineDataSet dataSet, LineData data,
                                         float chartMaxY, float chartMinY) {

            float fillMin = 0f;

            if (dataSet.getYMax() > 0 && dataSet.getYMin() < 0) {
                fillMin = 0f;
            } else {

                if (!getAxis(dataSet.getAxisDependency()).isStartAtZeroEnabled()) {

                    float max, min;

                    if (data.getYMax() > 0)
                        max = 0f;
                    else
                        max = chartMaxY;
                    if (data.getYMin() < 0)
                        min = 0f;
                    else
                        min = chartMinY;

                    fillMin = dataSet.getYMin() >= 0 ? min : max;
                } else {
                    fillMin = 0f;
                }

            }

            return fillMin;
        }
    }

    @Override
    public AJXAxis getXAxis() {
        return (AJXAxis) super.getXAxis();
    }

    @Override
    public AJYAxis getAxisLeft() {
        return (AJYAxis) super.getAxisLeft();
    }

    /**
     * 计算x间隔个数(随缩放变)
     */
    protected void calcModulus() {

        if (mXAxis == null || !mXAxis.isEnabled())
            return;

        if (!mXAxis.isAxisModulusCustom()) {

            float[] values = new float[9];
            mViewPortHandler.getMatrixTouch().getValues(values);

            final float size = getXAxis().getShowLabels().size();
            //   float a = size * mViewPortHandler.contentWidth() / (getHighestVisibleXIndex() - getLowestVisibleXIndex() + 1);

//            float b = a * values[Matrix.MSCALE_X] * mViewPortHandler.contentWidth();

//            mXAxis.mAxisLabelModulus = (int) Math
//                    .ceil((mBundle.getXValCount() * mXAxis.mLabelWidth)
//                            / (values[Matrix.MSCALE_X] *mViewPortHandler.contentWidth()));
//x轴坐标的总长度 /(图表宽 * x缩放比(默认最小铺满全屏下是1)) 相当于算出默认1 xsacle后,根据放缩比去获取其他的count值,便于理解
            int count = (int) Math
                    .ceil((mData.getXValCount() * mXAxis.mLabelWidth)
                            / (values[Matrix.MSCALE_X] * mViewPortHandler.contentWidth()));

//实际x预设坐标可能大于传入的数据个数
            mXAxis.mAxisLabelModulus = (int) Math
                    .ceil(size * count / (mData.getXValCount()));


//                mXAxis.mAxisLabelModulus = (int) Math
//                        .ceil(size / (count));
//            System.out.println("-->" + count + ',' + size + "," + mXAxis.mAxisLabelModulus);
        }

        if (mLogEnabled)
            Log.i(LOG_TAG, "X-Axis modulus: " + mXAxis.mAxisLabelModulus + ", x-axis label width: "
                    + mXAxis.mLabelWidth + ", content width: " + mViewPortHandler.contentWidth());

        if (mXAxis.mAxisLabelModulus < 1)
            mXAxis.mAxisLabelModulus = 1;
    }

    @Override
    public void setData(AJData data) {
        mRenderer = null;
        super.setData(data);
        mRenderer = new AJChartRenderer(this, mAnimator, mViewPortHandler);
        mRenderer.initBuffers();
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawLoadingMarker();
        drawVolumeMarkerView(canvas);
        drawValueMarker(canvas);
        drawButtonView(canvas);
        /*最大最小*/
        drawHighLowMarkerView(canvas);
//        Paint pan = new Paint();
//        pan.setColor(Color.RED);
//        pan.setStyle(Paint.Style.FILL);
//        canvas.drawRect(0, 0, 176, 96, pan);

    }

    /*最大最小*/
    private CandleEntry[] getCandleDataHighLow() {


        CandleEntry[] entries = new CandleEntry[2];

        if (getData() == null) {
            return entries;
        }

        CandleData candleData = getData().getCandleData();

        if (candleData == null || candleData.getDataSets() == null ||
                candleData.getDataSets().size() == 0) {
            return entries;
        }


        final int start = getLowestVisibleXIndex();
        final int end = getHighestVisibleXIndex();
        final List<CandleEntry> yVals = candleData.getDataSets().get(0).getYVals();
        int count = yVals.size();
        int endValue;
        if (end == 0)
            endValue = count - 1;
        else
            endValue = end;

        float min = Float.MAX_VALUE;
        float max = -Float.MIN_VALUE;


        for (int i = start; i <= endValue && i < count; i++) {


            CandleEntry e = yVals.get(i);

            if (e != null) {

                if (e.getLow() < min && !Float.isNaN(e.getLow())) {
                    min = e.getLow();
                    entries[0] = e;
                }

                if (e.getHigh() > max && !Float.isNaN(e.getHigh())) {
                    max = e.getHigh();
                    entries[1] = e;
                }
            }
        }

//        Collections.sort(temp, new Comparator<CandleEntry>() {
//            @Override
//            public int compare(CandleEntry lhs, CandleEntry rhs) {
//                if (Float.isNaN(lhs.getLow()) || Float.isNaN(rhs.getLow())) {
//                    return -1;
//                }
//                return lhs.getLow() > rhs.getLow() ? 1 : -1;
//            }
//        });
//
//        if (temp.size() != 0) {
//            entries[0] = temp.get(0);
//        }
//
//
//        Collections.sort(temp, new Comparator<CandleEntry>() {
//            @Override
//            public int compare(CandleEntry lhs, CandleEntry rhs) {
//                if (Float.isNaN(lhs.getHigh()) || Float.isNaN(rhs.getHigh())) {
//                    return 1;
//                }
//                return lhs.getHigh() > rhs.getHigh() ? -1 : 1;
//            }
//        });
//
//
//        if (temp.size() != 0) {
//            entries[1] = temp.get(0);
//        }


        return entries;
    }

    public void setQuoteInfoMarkerView(MarkerView quoteInfoMarkerView) {
        this.mQuoteInfoMarkerView = quoteInfoMarkerView;
    }

    public void setLeftMarkerView(MarkerView leftMarkerView) {
        this.mLeftMarkerView = leftMarkerView;
    }

    public void setRightMarkerView(MarkerView rightMarkerView) {
        this.mRightMarkerView = rightMarkerView;
    }

    public void setHighLightCircleView(HightCircleMarkerView highLightCircleView) {
        this.hightCircleMarkerView = highLightCircleView;
    }

    public void setXAxisMarkerView(MarkerView leftMarkerView) {
        this.mXAxisMarkerView = leftMarkerView;
    }

    /* 最大最小标记*/
    private void drawHighLowMarkerView(Canvas canvas) {
        if (mHighValueMarkerView == null || mLowValueMarkerView == null) {
            return;
        }
        CandleEntry[] entries = getCandleDataHighLow();

        CandleEntry maxEntry = entries[1];
        CandleEntry minEntry = entries[0];
        if (mHighValueMarkerView != null && maxEntry != null) {

            measureMarkerView(mHighValueMarkerView, 0, maxEntry);
            renderMarkView(canvas, mHighValueMarkerView, maxEntry, true);
        }


        if (mLowValueMarkerView != null && minEntry != null) {
            measureMarkerView(mLowValueMarkerView, 0, minEntry);
            renderMarkView(canvas, mLowValueMarkerView, minEntry, false);
        }
    }

    private void drawVolumeMarkerView(Canvas canvas) {
        if (mMaxVolumeMarkerView == null) {
            return;
        }
        CandleEntry[] entries = getCandleDataHighLow();

        CandleEntry maxEntry = entries[1];
        CandleEntry minEntry = entries[0];

        measureMarkerView(mMaxVolumeMarkerView, 0, maxEntry);
        renderMarkView(canvas, mMaxVolumeMarkerView, maxEntry, false);


    }

    /**
     * render MarkView
     *
     * @param canvas     canvas
     * @param markerView 显示的view
     * @param entry      数据集合
     * @param high       true:画在最高点，false：画在最低点
     */
    private void renderMarkView(Canvas canvas, MarkerView markerView, CandleEntry entry, boolean high) {
        float[] pos = {entry.getXIndex(), high ? entry.getHigh() : entry.getLow()};
        mLeftAxisTransformer.pointValuesToPixel(pos);
//        if (pos[1] - markerView.getHeight() <= 0) {
//            float y = markerView.getHeight() - pos[1];
//            markerView.draw(canvas, pos[0], pos[1] + y);
//        } else {
//            markerView.draw(canvas, pos[0], pos[1]);
//        }

        float x = 0, y = 0;
        if ((pos[0] - markerView.getWidth() - mIndicateLength) < mViewPortHandler.contentLeft()) {
            canvas.drawLine(pos[0], pos[1], pos[0] + mIndicateLength, pos[1], mIndicatePaint);

            if (pos[1] + markerView.getXOffset() < mViewPortHandler.contentTop()) {
                x = pos[0] + mIndicateLength - markerView.getXOffset();
                y = mViewPortHandler.contentTop() + markerView.getXOffset();
            } else {
                x = pos[0] + mIndicateLength - markerView.getXOffset();
                y = pos[1];
            }

        } else {
            canvas.drawLine(pos[0] - mIndicateLength, pos[1], pos[0], pos[1], mIndicatePaint);
//            markerView.draw(canvas, pos[0] + mIndicateLength, pos[1]);
            if (pos[1] + markerView.getXOffset() < mViewPortHandler.contentTop()) {
                x = pos[0] - mIndicateLength - markerView.getWidth() - markerView.getXOffset();
                y = mViewPortHandler.contentTop() + markerView.getXOffset();
            } else {
                x = pos[0] - mIndicateLength - markerView.getWidth() - markerView.getXOffset();
                y = pos[1];
            }
        }

        markerView.draw(canvas, x, y);


    }

    private void measureMarkerView(MarkerView markerView, int dataSetIndex, Entry e) {
        markerView.refreshContent(e, dataSetIndex);
        markerView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        markerView.layout(0, 0, markerView.getMeasuredWidth(), markerView.getMeasuredHeight());
    }

    /*loading更多*/
    protected void drawLoadingMarker() {

        if (loadingMarkView == null) {
            return;
        }

        if (getData() == null) {
            loadingMarkView.layout(0, 0, 0, 0);
            return;
        }

        float spaceX = mViewPortHandler.getDragOffsetX();


        Matrix matrix = mViewPortHandler.getMatrixTouch();
        float[] val = getMatrixValues(matrix);

        float x = val[Matrix.MTRANS_X];
        if (spaceX == 0) {
            loadingMarkView.layout(0, 0, 0, 0);
            return;
        }

//        Entry e = mBundle.getDataSets().get(0).getEntryForXIndex(0);
//        float[] pos = getMarkerPosition(e, 0);


        int offsetY = (int) ((mViewPortHandler.getContentRect().height() - loadingMarkView.getMeasuredHeight()) / 2 + mViewPortHandler.offsetTop());

        int offsetX = (int) (mViewPortHandler.contentLeft() + (spaceX - loadingMarkView.getMeasuredWidth()) / 2);
//        loadingMarkView.draw(canvas, pos[0], 0);

        int width = (int) Math.min(Math.max(x - (spaceX - loadingMarkView.getMeasuredWidth()) / 2, 0), loadingMarkView.getMeasuredWidth());
        int height = loadingMarkView.getMeasuredHeight();

        loadingMarkView.layout(offsetX, offsetY, offsetX + width,
                offsetY + height);

    }

    @Override
    public void computeScroll() {

        mKLineTouchListener.computeScroll();
    }

    public void closeLoadingView() {
//        mMarketTouchListener.complieLoading();
        mKLineTouchListener.closeLoading();

    }

    @Override
    public boolean getDrawbarEnable() {
        return true;
    }

    @Override
    public boolean getHighLightStyle() {
        return mHighlightStyle;
    }

    public void setOnLoadingViewListener(AJChartTouchListener.OnLoadingViewListener l) {
        mKLineTouchListener.setOnLoadingViewListener(l);
    }

    public void setLoadingViewOpen(boolean open) {
        mKLineTouchListener.setLoadingViewOpen(open);
    }

    int select;

    public Entry highlightTouchWithoutEvent(Highlight high, int isSelect) {
        this.select = isSelect;
        Entry e = null;
        if (high == null) {
            Log.e("tenface", "getXValCount: " + mData.getXValCount());
            if (isSelect == 1) {
                mIndicesToHightlight = new Highlight[]{new Highlight(mData.getXValCount() - 1, 0)};
            } else {
                mIndicesToHightlight = null;
            }
        } else {
            Log.e("tenface", "getDataSetIndex: " + high.getDataSetIndex() + "getStackIndex:" + high.getStackIndex() + "getValuePosition:" + high.getValuePosition() + "getXIndex:" + high.getXIndex());
            if (mLogEnabled)
                Log.i(LOG_TAG, "Highlighted: " + high.toString());

            e = mData.getEntryForHighlight(high);
            if (e == null || e.getXIndex() != high.getXIndex()) {
                if (isSelect == 1) {
                    mIndicesToHightlight = new Highlight[]{new Highlight(mData.getXValCount() - 1, 0)};
                } else {
                    mIndicesToHightlight = null;
                }
                high = null;
            } else {
                // set the indices to highlight
                mIndicesToHightlight = new Highlight[]{
                        high
                };
            }
        }
        // redraw the com.mp.chart
        invalidate();
        return e;
    }

    public void setHighValueMarkerView(MarkerView v) {
        this.mHighValueMarkerView = v;
    }

    public void setHighValueMarkerViewVisibility(boolean visibility) {
        markerViewIsVisibility = visibility;
        if (mHighValueMarkerView != null) {
            if (markerViewIsVisibility) {
                mHighValueMarkerView.setVisibility(VISIBLE);
            } else {
                mHighValueMarkerView.setVisibility(GONE);
            }
        }
    }

    public void setMaxVolumeMarkerView(MarkerView v) {
        this.mMaxVolumeMarkerView = v;
    }


    public void setLowValueMarkerView(MarkerView v) {
        this.mLowValueMarkerView = v;
    }


    @Override
    public OnScrollDataListener getOnScrollDataListener() {
        return mOnScrollDataListener;
    }

    @Override
    public void setOnScrollDataListener(OnScrollDataListener l) {
        this.mOnScrollDataListener = l;
    }

    public void setOnSyncChartListener(OnSyncChartListener l) {
        mKLineTouchListener.setOnSyncChartListener(l);
    }


    private float[] getMatrixValues(Matrix matrix) {
        float[] val = new float[9];
        matrix.getValues(val);
        return val;
    }

    @Override
    public void syncMatrix(float transx, float scalex, boolean islimit) {
        mKLineTouchListener.performScrollData();
        mKLineTouchListener.prepareSync();
        Matrix matrix = mViewPortHandler.getMatrixTouch();
        float[] val = getMatrixValues(matrix);

        val[Matrix.MTRANS_X] = transx;
        val[Matrix.MSCALE_X] = scalex;

        matrix.setValues(val);
        if (!islimit) {
            invalidate();
        } else {
            mViewPortHandler.refresh(matrix, this, true);
        }
    }

    @Override
    protected void calcMinMax() {
        super.calcMinMax();


        if (getBollData() != null || getBarData() != null || getCandleData() != null || getBubbleData() != null) {
            mXChartMin = -0.5f;
            mXChartMax = mData.getXVals().size() - 0.5f;


            if (getBubbleData() != null) {

                for (BubbleDataSet set : getBubbleData().getDataSets()) {

                    final float xmin = set.getXMin();
                    final float xmax = set.getXMax();

                    if (xmin < mXChartMin)
                        mXChartMin = xmin;

                    if (xmax > mXChartMax)
                        mXChartMax = xmax;
                }
            }
            mDeltaX = Math.abs(mXChartMax - mXChartMin);
        }


        if (getAxisLeft().isShowBaseValueAndMaxmin()) {
            getAxisLeft().setBaseValue(0);
            float y = Math.max(Math.abs(mAxisLeft.mAxisMaximum), Math.abs(mAxisLeft.mAxisMinimum));
            mAxisLeft.mAxisMaximum = y;
            mAxisLeft.mAxisMinimum = -y;
            mAxisLeft.mAxisRange = Math.abs(mAxisLeft.mAxisMaximum - mAxisLeft.mAxisMinimum);
            mAxisRight.mAxisRange = Math.abs(mAxisRight.mAxisMaximum - mAxisRight.mAxisMinimum);
        }

    }

    public void setLoadingMarkerView(LoadingMarkerView loadingMarkView) {

        if (loadingMarkView == null) {
            return;
        }

        if (this.loadingMarkView != null) {
            removeView(this.loadingMarkView);
        }

        this.loadingMarkView = loadingMarkView;
        this.loadingMarkView.refreshView();
        addView(this.loadingMarkView);

    }

    @Override
    public void setVisibleXRange(float minXRange, float maxXRange) {
        this.minXRange = minXRange;
        this.maxXRange = maxXRange;
        super.setVisibleXRange(minXRange, maxXRange);
    }

    @Override
    public void setVisibleXRangeMinimum(float minXRange) {
        this.minXRange = minXRange;
        super.setVisibleXRangeMinimum(minXRange);
    }

    @Override
    public void setVisibleXRangeMaximum(float maxXRange) {
        this.maxXRange = maxXRange;
        super.setVisibleXRangeMaximum(maxXRange);
    }

    public float getVisibleXRangeMaximum() {
        return this.maxXRange;
    }


    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();

        if (this.minXRange != -1) {
            super.setVisibleXRangeMinimum(minXRange);
        }

        if (this.maxXRange != -1) {
            super.setVisibleXRangeMaximum(maxXRange);
        }
    }

    @Override
    public void setOnTouchListener(ChartTouchListener l) {
        super.setOnTouchListener(l);
        mKLineTouchListener = (AJChartTouchListener) l;
    }

    public void setValueMarkerView(ValueMarkerView markerview) {
        this.valueMarkerView = markerview;

        valueMarkerView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

        int top = valueMarkerView.getMeasuredHeight();


        float srcTop = getExtraTopOffset();
        if (top > srcTop) {
            setExtraTopOffset(Utils.convertPixelsToDp(top));
        }

    }

    public void setButtonView(MarkerView markerView) {


        this.buttonView = markerView;

        if (this.buttonView != null) {
            removeView(this.buttonView);
        }

        if (markerView == null) {
            return;
        }


        this.buttonView = markerView;
        this.buttonView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
//        addView(this.buttonView);
        int top = this.buttonView.getMeasuredHeight();
        float srcTop = getExtraTopOffset();
        if (top > srcTop) {
            setExtraTopOffset(Utils.convertPixelsToDp(top));
        }

    }

    private void drawButtonView(Canvas canvas) {
        if (this.buttonView == null) {
            return;
        }
        int startY = (int) (getViewPortHandler().contentTop() - this.buttonView.getMeasuredHeight());
        int startX = (int) getViewPortHandler().contentLeft();
        this.buttonView.layout(startX, startY, this.buttonView.getMeasuredWidth(), this.buttonView.getMeasuredHeight());

        this.buttonView.draw(canvas, mViewPortHandler.contentLeft(), mViewPortHandler.contentTop() + 1);
    }

    /*柱状图选中值（当前交易量）*/
    private void drawValueMarker(Canvas canvas) {
        if (valueMarkerView == null || !valuesToHighlight() || mData == null) {
            return;
        }
        for (int i = 0; i < mIndicesToHightlight.length; i++) {
            int xIndex = mIndicesToHightlight[i].getXIndex();
            int dataSetIndex = mIndicesToHightlight[i].getDataSetIndex();

            if (xIndex <= mDeltaX && xIndex <= mDeltaX * mAnimator.getPhaseX()) {

                Entry e = mData.getEntryForHighlight(mIndicesToHightlight[i]);

                // make sure entry not null
                if (e == null || e.getXIndex() != mIndicesToHightlight[i].getXIndex())
                    continue;

                float[] pos = getMarkerPosition(e, dataSetIndex);

                // check bounds
                if (!mViewPortHandler.isInBounds(pos[0], pos[1]))
                    continue;

                valueMarkerView.setMarkViewPosition(valueMarkerViewPosition);
                measureMarkerView(valueMarkerView, dataSetIndex, e);
                /*显示在左边*/
//                if (valueMarkerViewPosition == ValueMarkerViewPosition_Left) {
                valueMarkerView.draw(canvas, mViewPortHandler.contentLeft(), mViewPortHandler.contentTop() + 1);
//                } else {
//                    valueMarkerView.draw(canvas, mViewPortHandler.contentRight() - valueMarkerView.getWidth() - 2, 3);
//                }
                /*默认直接设置在右边*/
                // valueMarkerView.draw(canvas, mViewPortHandler.contentRight() - valueMarkerView.getWidth(), getViewPortHandler().contentTop() - valueMarkerView.getHeight());


            }


        }

    }

    //    /**
//     * Returns the Highlight object (contains x-index and DataSet index) of the
//     * selected showapi_res_body at the given touch point inside the Line-, Scatter-, or
//     * CandleStick-Chart.
//     * 根据touch折线图设置高亮显示
//     *
//     * @param x
//     * @param y
//     * @return
//     */
//    public Highlight getHighlightByTouchPoint(float x, float y) {
//
//        if (mDataNotSet || mData == null) {
//            Log.e(LOG_TAG, "Can't select by touch. No data set.");
//            return null;
//        }
//
//        // create an array of the touch-point
//        float[] pts = new float[2];
//        pts[0] = x;
//
//        // take any transformer to determine the x-axis showapi_res_body
//        mLeftAxisTransformer.pixelsToValue(pts);
//
//        double xTouchVal = pts[0];
//
//        double base = Math.floor(xTouchVal);
//
//        double touchOffset = mDeltaX * 0.025;
//
//        // touch out of com.mp.chart
//        if (xTouchVal < -touchOffset || xTouchVal > mDeltaX + touchOffset)
//            return null;
//
//        if (base < 0)
//            base = 0;
//        if (base >= mDeltaX)
//            base = mDeltaX - 1;
//
//        int xIndex = (int) base;
//
//        // check if we are more than half of a x-showapi_res_body or not
//        if (xTouchVal - base > 0.5) {
//            xIndex = (int) base + 1;
//        }
//
//        List<SelectionDetail> valsAtIndex = getSelectionDetailsAtIndex(xIndex);
//        float leftdist = Utils.getMinimumDistance(valsAtIndex, y, YAxis.AxisDependency.LEFT);
//        float rightdist = Utils.getMinimumDistance(valsAtIndex, y, YAxis.AxisDependency.RIGHT);
//
//        if (mData.getFirstRight() == null)
//            rightdist = Float.MAX_VALUE;
//        if (mData.getFirstLeft() == null)
//            leftdist = Float.MAX_VALUE;
//
//        YAxis.AxisDependency axis = leftdist < rightdist ? YAxis.AxisDependency.LEFT : YAxis.AxisDependency.RIGHT;
//
//        int dataSetIndex = Utils.getClosestDataSetIndex(valsAtIndex, y, axis);
//        Log.e("tenface", "dataSetIndex" + dataSetIndex);
////        if (dataSetIndex == -1)
////            return new Highlight(xIndex, 0);
//        /*修复数据不全情况下,快速高亮滑动导致高亮不在最右侧的bug*/
//        if (dataSetIndex == -1) {
//            xIndex = getValueCount() - 1;
//            dataSetIndex = 0;
//            highlightTouch(new Highlight(xIndex, dataSetIndex));
//            Log.e("tenface", "xIndex: " + xIndex);
//            /*空白处设置高亮值*/
//            highlightValues(new Highlight[]{
//                    new Highlight(xIndex, dataSetIndex)
//            });
//        }
//        return new Highlight(xIndex, dataSetIndex);
//    }
    @Override
    public Highlight getHighlightByTouchPoint(float x, float y) {
//        Log.e("tenface-", "x: " + x + ",y:" + y);

//        Log.e("tenface-", "VPHx: " + mViewPortHandler.getContentCenter().x);

        if (mViewPortHandler.getContentCenter().x < x) {
            this.valueMarkerViewPosition = ValueMarkerViewPosition_Left;
//            Log.e("tenface-", "xIndex: " + valueMarkerViewPosition);
        } else {
            this.valueMarkerViewPosition = ValueMarkerViewPosition_Right;
//            Log.e("tenface-", "xIndex: " + valueMarkerViewPosition);
        }


        Highlight h = super.getHighlightByTouchPoint(x, y);
        if (h != null) {
            h.setValuePosition(this.valueMarkerViewPosition);
//            Log.e("tenface-", "h != null: h=" + valueMarkerViewPosition);
        }
        return h;

    }

    public void setValueMarkerViewPosition(int valueMarkerViewPosition) {
        this.valueMarkerViewPosition = valueMarkerViewPosition;
    }


    public void restoreScale() {
        Matrix matrix = mViewPortHandler.getMatrixTouch();

        matrix.setScale(1, 1);


        mViewPortHandler.refresh(matrix, this, false);
    }

    @Override
    protected void drawMarkers(Canvas canvas) {

        // if there is no marker view or drawing marker is disabled

        if (mQuoteInfoMarkerView == null && mLeftMarkerView == null && mRightMarkerView == null && mMarkerView == null && mXAxisMarkerView == null) {
            return;
        }


        if (!mDrawMarkerViews || !valuesToHighlight())
            return;

        for (int i = 0; i < mIndicesToHightlight.length; i++) {

            int xIndex = mIndicesToHightlight[i].getXIndex();
            int dataSetIndex = mIndicesToHightlight[i].getDataSetIndex();

            if (xIndex <= mDeltaX && xIndex <= mDeltaX * mAnimator.getPhaseX()) {

                Entry e = mData.getEntryForHighlight(mIndicesToHightlight[i]);

                // make sure entry not null
                if (e == null || e.getXIndex() != mIndicesToHightlight[i].getXIndex())
                    continue;

                float[] pos = getMarkerPosition(e, dataSetIndex);
                float[] posK = new float[0];
                if (!mViewPortHandler.isInBoundsX(pos[0])) {
                    continue;
                }
                if ("kline".equals(marketChartType)) {
                    CandleEntry candleEntry = (CandleEntry) mData.getEntryForHighlight(mIndicesToHightlight[i]);
                    float close = candleEntry.getClose();
                    posK = new float[]{xIndex, close};
                    mLeftAxisTransformer.pointValuesToPixel(posK);//将点坐标转换为px
                }//只显示左边
                if (mLeftMarkerView != null && mRightMarkerView == null) {
                    measureMarkerView(mLeftMarkerView, dataSetIndex, e);
                    if ("timeline".equals(marketChartType)) {
                        float x = 0;
                        float y = 0;
                    /*如果高亮的x>图表的中心宽，则显示在左边  centerX是以图表的左下角为来算的px单位*/
                        if (pos[0] > mViewPortHandler.getContentRect().centerX()) {

                            //x = mViewPortHandler.contentLeft() - mLeftMarkerView.getXOffset();
                            x = mViewPortHandler.contentLeft() - mLeftMarkerView.getXOffset() - mLeftMarkerView.getWidth();
                        } else {
                            //x = mViewPortHandler.contentRight() + mLeftMarkerView.getXOffset() - mLeftMarkerView.getWidth();
                            x = mViewPortHandler.contentRight() + mLeftMarkerView.getXOffset();
                        }
                        if (pos[1] + mLeftMarkerView.getYOffset() < mViewPortHandler.contentTop()) {
                            y = mViewPortHandler.contentTop() - mLeftMarkerView.getYOffset();
                        } else if (pos[1] - mLeftMarkerView.getYOffset() > mViewPortHandler.contentBottom()) {
                            y = mViewPortHandler.contentBottom() + mLeftMarkerView.getYOffset();
                        } else {
                            y = pos[1];
                        }
                        mLeftMarkerView.draw(canvas, x, y);
                    } else if ("kline".equals(marketChartType)) {
                        if (posK[1] + mLeftMarkerView.getYOffset() < mViewPortHandler.contentTop()) {
                            //mLeftMarkerView.draw(canvas, mViewPortHandler.offsetLeft(), mViewPortHandler.contentTop() - mLeftMarkerView.getYOffset());
                            mLeftMarkerView.draw(canvas, mViewPortHandler.contentLeft() - mViewPortHandler.offsetLeft() - mLeftMarkerView.getWidth(), mViewPortHandler.contentTop() - mLeftMarkerView.getYOffset());
                        } else if (posK[1] - mLeftMarkerView.getYOffset() > mViewPortHandler.contentBottom()) {
                            //mLeftMarkerView.draw(canvas, mViewPortHandler.offsetLeft(), mViewPortHandler.contentBottom() + mLeftMarkerView.getYOffset());
                            mLeftMarkerView.draw(canvas, mViewPortHandler.contentLeft() - mViewPortHandler.offsetLeft() - mLeftMarkerView.getWidth(), mViewPortHandler.contentBottom() + mLeftMarkerView.getYOffset());
                        } else {
                            mLeftMarkerView.draw(canvas, mViewPortHandler.contentLeft() - mLeftMarkerView.getWidth(), posK[1] - mLeftMarkerView.getHeight() / 2);
                        }
                    }

                    /*mleftMarkerView==null || mrightMarkerView!=null && mleftMarkerView!=null 等价于后面两个交集*/
                    /*左右边有 限制左边，右边下面进行限制*/
                }

                if (mLeftMarkerView != null) {
                    measureMarkerView(mLeftMarkerView, dataSetIndex, e);
                    if ("timeline".equals(marketChartType)) {
                        if (pos[1] + mLeftMarkerView.getYOffset() < mViewPortHandler.contentTop()) {
                            //mLeftMarkerView.draw(canvas, mViewPortHandler.offsetLeft(), mViewPortHandler.contentTop() - mLeftMarkerView.getYOffset());
                            mLeftMarkerView.draw(canvas, mViewPortHandler.contentLeft() - mViewPortHandler.offsetLeft() - mLeftMarkerView.getWidth(), mViewPortHandler.contentTop() - mLeftMarkerView.getYOffset());
                        } else if (pos[1] - mLeftMarkerView.getYOffset() > mViewPortHandler.contentBottom()) {
                            //mLeftMarkerView.draw(canvas, mViewPortHandler.offsetLeft(), mViewPortHandler.contentBottom() + mLeftMarkerView.getYOffset());
                            mLeftMarkerView.draw(canvas, mViewPortHandler.contentLeft() - mViewPortHandler.offsetLeft() - mLeftMarkerView.getWidth(), mViewPortHandler.contentBottom() + mLeftMarkerView.getYOffset());
                        } else {
                            mLeftMarkerView.draw(canvas, mViewPortHandler.contentLeft() - mLeftMarkerView.getWidth(), pos[1] - mLeftMarkerView.getHeight() / 2);
                        }
                    } else if ("kline".equals(marketChartType)) {//kchart
                        if (posK[1] + mLeftMarkerView.getYOffset() < mViewPortHandler.contentTop()) {
                            //mLeftMarkerView.draw(canvas, mViewPortHandler.offsetLeft(), mViewPortHandler.contentTop() - mLeftMarkerView.getYOffset());
                            mLeftMarkerView.draw(canvas, mViewPortHandler.contentLeft() - mViewPortHandler.offsetLeft() - mLeftMarkerView.getWidth(), mViewPortHandler.contentTop() - mLeftMarkerView.getYOffset());
                        } else if (posK[1] - mLeftMarkerView.getYOffset() > mViewPortHandler.contentBottom()) {
                            //mLeftMarkerView.draw(canvas, mViewPortHandler.offsetLeft(), mViewPortHandler.contentBottom() + mLeftMarkerView.getYOffset());
                            mLeftMarkerView.draw(canvas, mViewPortHandler.contentLeft() - mViewPortHandler.offsetLeft() - mLeftMarkerView.getWidth(), mViewPortHandler.contentBottom() + mLeftMarkerView.getYOffset());
                        } else {
                            mLeftMarkerView.draw(canvas, mViewPortHandler.contentLeft() - mLeftMarkerView.getWidth(), posK[1] - mLeftMarkerView.getHeight() / 2);
                        }
                    }

                }

                if (mRightMarkerView != null) {
                    measureMarkerView(mRightMarkerView, dataSetIndex, e);
                    if ("timeline".equals(marketChartType)) {
                        if (pos[1] + mRightMarkerView.getYOffset() < mViewPortHandler.contentTop()) {
                            mRightMarkerView.draw(canvas, mViewPortHandler.contentRight() - mViewPortHandler.offsetLeft() + mRightMarkerView.getWidth(), mViewPortHandler.contentTop() - mRightMarkerView.getYOffset());
                        } else if (pos[1] - mLeftMarkerView.getYOffset() > mViewPortHandler.contentBottom()) {
                            mRightMarkerView.draw(canvas, mViewPortHandler.contentRight() - mViewPortHandler.offsetLeft() + mRightMarkerView.getWidth(), mViewPortHandler.contentBottom() + mRightMarkerView.getYOffset());
                        } else {
                            mRightMarkerView.draw(canvas, mViewPortHandler.contentRight(), pos[1] - mLeftMarkerView.getHeight() / 2);
                        }
                    } else if ("kline".equals(marketChartType)) {//kchart
                        if (posK[1] + mRightMarkerView.getYOffset() < mViewPortHandler.contentTop()) {
                            mRightMarkerView.draw(canvas, mViewPortHandler.contentRight() - mViewPortHandler.offsetLeft() + mRightMarkerView.getWidth(), mViewPortHandler.contentTop() - mRightMarkerView.getYOffset());
                        } else if (posK[1] - mLeftMarkerView.getYOffset() > mViewPortHandler.contentBottom()) {
                            mRightMarkerView.draw(canvas, mViewPortHandler.contentRight() - mViewPortHandler.offsetLeft() + mRightMarkerView.getWidth(), mViewPortHandler.contentBottom() + mRightMarkerView.getYOffset());
                        } else {
                            mRightMarkerView.draw(canvas, mViewPortHandler.contentRight(), posK[1] - mLeftMarkerView.getHeight() / 2);
                        }
                    }
                }


            /*    // check bounds
                if (!mViewPortHandler.isInBounds(pos[0], pos[1])) {
                    System.out.println("isInBounds");
                    continue;
                }*/

                // callbacks to update the content

                if (mMarkerView != null) {
                    measureMarkerView(mMarkerView, dataSetIndex, e);

                    float x = 0;
                    float y = 0;
                    if (pos[0] > mViewPortHandler.getContentRect().centerX()) {
                        x = mViewPortHandler.contentLeft() - mMarkerView.getXOffset();
                    } else {
                        x = mViewPortHandler.contentRight() + mMarkerView.getXOffset() - mMarkerView.getWidth();
                    }

                    if (pos[1] + mMarkerView.getYOffset() < mViewPortHandler.contentTop()) {
                        y = mViewPortHandler.contentTop() - mMarkerView.getYOffset();
                    } else if (pos[1] - mMarkerView.getYOffset() > mViewPortHandler.contentBottom()) {
                        y = mViewPortHandler.contentBottom() + mMarkerView.getYOffset();
                    } else {
                        y = pos[1];
                    }
                    mMarkerView.draw(canvas, x, y);
                }

/*k线图 x轴*/
                if (mXAxisMarkerView != null) {
                    measureMarkerView(mXAxisMarkerView, dataSetIndex, e);
                    float x = pos[0];
                    float y = mViewPortHandler.contentBottom();

                    if (pos[0] + mXAxisMarkerView.getXOffset() < mViewPortHandler.contentLeft()) {
                        x = mViewPortHandler.contentLeft() - mXAxisMarkerView.getXOffset();
                    } else if (pos[0] - mXAxisMarkerView.getXOffset() > mViewPortHandler.contentRight()) {
                        x = mViewPortHandler.contentRight() + mXAxisMarkerView.getXOffset();
                    } else {
                        x = pos[0];
                    }

//                    if (pos[1] - mXAxisMarkerView.getYOffset() + mXAxisMarkerView.getHeight() > mViewPortHandler.contentBottom()) {
//                        y = mViewPortHandler.contentTop() - mXAxisMarkerView.getYOffset();
//                    } else {
//                        y = mViewPortHandler.contentBottom() - mXAxisMarkerView.getHeight() - mXAxisMarkerView.getYOffset();
//                    }


                    mXAxisMarkerView.draw(canvas, x, y);


                }

                /*TenFace:高亮圆点*/
                if (hightCircleMarkerView != null && "kline".equals(marketChartType)) {
//                    Log.e("#######", posK[0] - hightCircleMarkerView.getMeasuredWidth() + "," + (posK[1] - hightCircleMarkerView.getMeasuredHeight()));
                    hightCircleMarkerView.draw(canvas, posK[0] - hightCircleMarkerView.getMeasuredWidth(), posK[1] - hightCircleMarkerView.getMeasuredHeight());
                    hightCircleMarkerView.draw(canvas, posK[0] - hightCircleMarkerView.getMeasuredWidth(), posK[1] - hightCircleMarkerView.getMeasuredHeight());

                }

                if (mQuoteInfoMarkerView != null) {
                    drawQuoteInfoView(canvas, i, xIndex, e, pos);
                }

//                if (pos[1] - mMarkerView.getHeight() <= 0) {
//                    float y = mMarkerView.getHeight() - pos[1];
//                    mMarkerView.draw(canvas, pos[0], pos[1] + y);
//                } else {
//                    mMarkerView.draw(canvas, pos[0], pos[1]);
//                }
            }
        }
    }

    /***
     * 画chart上的悬浮view
     * @param canvas canvas
     * @param i for循环索引
     * @param xIndex  数据索引
     * @param e Entry
     */
    private void drawQuoteInfoView(Canvas canvas, int i, int xIndex, Entry e, float[] pos) {
        if (mQuoteInfoMarkerView != null) {
            if ("timeline".equals(marketChartType)) {
                mQuoteInfoMarkerView.refreshContent(e, i);
                mQuoteInfoMarkerView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                mQuoteInfoMarkerView.layout(0, 0, mQuoteInfoMarkerView.getMeasuredWidth(), mQuoteInfoMarkerView.getMeasuredHeight());
                if (xIndex >= 0 && xIndex < 180) {
                    mQuoteInfoMarkerView.draw(canvas, mViewPortHandler.contentWidth() - mQuoteInfoMarkerView.getWidth() + mViewPortHandler.offsetLeft(), mViewPortHandler.contentTop() - mViewPortHandler.offsetTop());
                } else if (xIndex >= 180) {
                    mQuoteInfoMarkerView.draw(canvas, mViewPortHandler.contentLeft(), mViewPortHandler.contentTop() - mViewPortHandler.offsetTop());
                }
            } else if ("kline".equals(marketChartType)) {
                mQuoteInfoMarkerView.refreshContent(e, i);
                mQuoteInfoMarkerView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                mQuoteInfoMarkerView.layout(0, 0, mQuoteInfoMarkerView.getMeasuredWidth(), mQuoteInfoMarkerView.getMeasuredHeight());
//                Log.e("drawQuoteInfoView:pos[0]=", pos[0] + ",pos[1]" + pos[1] + ",posK[0]=" + posK[0] + ",posK[1]" + posK[1]);
                if (pos[0] >= 0 && pos[0] < 500) {
                    mQuoteInfoMarkerView.draw(canvas, mViewPortHandler.contentWidth() - mQuoteInfoMarkerView.getWidth() + mViewPortHandler.offsetLeft(), mViewPortHandler.contentTop() - mViewPortHandler.offsetTop() + 60);
                } else if (pos[0] >= 500) {
                    mQuoteInfoMarkerView.draw(canvas, mViewPortHandler.contentLeft(), mViewPortHandler.contentTop() - mViewPortHandler.offsetTop() + 60);
                }
            }
        }
    }

    public void setHighlightStyle(boolean b) {
        mHighlightStyle = b;
    }

    @Override
    public void moveViewToX(float xIndex) {


        float yValue = 0f;

        float[] pts = new float[]{
                xIndex, yValue
        };

        getTransformer(YAxis.AxisDependency.LEFT).pointValuesToPixel(pts);
        mViewPortHandler.centerViewPort(pts, this);

    }


}